// Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
#include <iostream>
#include <vector>
#include <chrono>
#include <thread>

#include "acl/acl.h"
#include "acl/acl_op_compiler.h"
#include "graph/operator_reg.h"

#define CALL_RT(x)                                                                                                     \
    if (auto ret = (x) != 0) {                                                                                         \
        std::cout << "[ERROR] Failed to exec acl api " << #x << ", result: " << ret << std::endl;                      \
        return -1;                                                                                                     \
    } else {                                                                                                           \
        std::cout << "[INFO] Succeeded to exec acl api " << #x << std::endl;                                           \
    }

#define LOG_INFO(FMT, ...) printf("[INFO] " FMT "\n", __VA_ARGS__)

int main()
{
    // init acl
    CALL_RT(aclInit(nullptr));
    CALL_RT(aclrtSetDevice(0));

    aclrtStream stream;
    CALL_RT(aclrtCreateStream(&stream));

    // init tensor desc
    int len = 1000000;
    std::vector<int64_t> inputShape{len};
    aclTensorDesc *inputDescs[1];
    inputDescs[0] = aclCreateTensorDesc(ACL_INT32.inputShape.size(), inputShape.data(), ACL_FORMAT_ND);
    std::vector<int64_t> outputShape{len};
    aclTensorDesc *outputDescs[1];
    outputDescs[0] = aclCreateTensorDesc(ACL_INT32, outputShape.size(), outputShape.data(), ACL_FORMAT_ND);

    // init tensor buffer
    void *inputDevice;
    CALL_RT(aclrtMalloc(&inputDevice, len * sizeof(int), ACL_MEM_MALLOC_HUGE_FIRST));
    std::vector<int> inputHost(len);
    printf("inputs: ");
    for (int i = 0; i < len; ++i) {
        inputHost[i] = i - len;
    }
    CALL_RT(aclrtMemcpy(inputDevice, len * sizeof(int), inputHost.data(), len * sizeof(int),
        ACL_MEMCPY_HOST_TO_DEVICE));
    void *outputDevice;
    CALL_RT(aclrtMalloc(&outputDevice, len * sizeof(int), ACL_MEM_MALLOC_HUGE_FIRST));

    std::vector<aclDataBuffer *> inBuffers;
    aclDataBuffer *inputBuffer = aclCreateDataBuffer(inputDevice, len * sizeof(int));
    if (inputBuffer == nullptr) {
        std::cout << "[ERROR] Failed to create input buffer" << std::endl;
        return -1;
    }
    inBuffers.push_back(inputBuffer);
    std::vector<aclDataBuffer *> outBuffers;
    aclDataBuffer *outputBuffer = aclCreateDataBuffer(outputDevice, len * sizeof(int));
    if (outputBuffer == nullptr) {
        std::cout << "[ERROR] Failed to create output buffer" << std::endl;
        return -1;
    }
    outBuffers.push_back(outputBuffer);
    std::cout << "[INFO] Succeeded to create buffers" << std::endl;

    // compile and execute op
    CALL_RT(aclopSetCompileFlag(ACL_OP_COMPILE_FUZZ));
    CALL_RT(aclopCompileAndExecuteV2("Relu7", 1, inputDescs, inBuffers.data(), 1, outputDescs, outBuffers.data(),
                                     nullptr, ACL_ENGINE_SYS, ACL_COMPILE_SYS, NULL, stream));

    CALL_RT(aclrtSynchronizeStream(stream));

    std::vector<int> outputHost(len, 0);
    CALL_RT(aclrtMemcpy(outputHost.data(), len * sizeof(int), outputDevice, len * sizeof(int),
        ACL_MEMCPY_DEVICE_TO_HOST));
}
